home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d886.lha / TextPort / source / Reformat.c < prev    next >
C/C++ Source or Header  |  1993-07-16  |  8KB  |  210 lines

  1. /*------------------------------------------------------------+
  2.  | reformat.c -- 5/16/1992 public domain                      |
  3.  |             by Alex Matulich, Unicorn Research Corporation |
  4.  | Reformat a text file with different line lenghts.  Original|
  5.  | hard carriage returns are deleted and new ones added in,   |
  6.  | depending on specified line width.  Original hard returns  |
  7.  | will be kept in the file if:                               |
  8.  |       (1)   They are followed by whitespace,               |
  9.  |       (2)   They are preceded by a newlines, or            |
  10.  |       (3)   They are on a shorter line than the specified  |
  11.  |             width, and re-wrapping is not specified.       |
  12.  | For this program to work, the EOL code in the text must be |
  13.  | with the OS being run.  Use StripCR or AddCR as necessary. |
  14.  +------------------------------------------------------------*/
  15.                                                 
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <ctype.h>
  19. #define OUTBUFSIZ 24000
  20.  
  21. unsigned long outbufsiz = OUTBUFSIZ;
  22. unsigned short replace, bufptr = 0, lineptr = 0;
  23. signed char *buf = NULL;
  24. FILE *infile, *outfile;
  25. long inpos = 0L, outpos = 0L;       /* file position trackers */
  26.  
  27. int writebuf(void);
  28.  
  29.  
  30. void main(int argc, char *argv[])
  31. {
  32. short j, err = 0, linelength = 72, tabwidth = 8, reformshort = 0, cntinu = 0,
  33.    plast, ptr = 1, pnext;  /* pointers to characters in lookahead buffer */
  34. signed char lk[3];         /* lookahead buffer */
  35.  
  36. if (argc < 2 || argc > 5) err = 3;
  37. if (!err) {
  38.    short i = 0;
  39.    while (!err && ++i < argc)        /* process any commandline switches */
  40.       if (*argv[i] == '-') {
  41.          if (argv[i][1] == 'l' || argv[i][1] == 'L') {      /* line length */
  42.             linelength = atoi(&argv[i][2]);
  43.             if (linelength < 32) err = 3;
  44.             if (linelength >= OUTBUFSIZ) outbufsiz = linelength;
  45.             }
  46.          else if (argv[i][1] == 't' || argv[i][1] == 'T') { /* tab width */
  47.             if ((tabwidth = atoi(&argv[i][2])) > 30) err = 3;
  48.             }
  49.          else if (argv[i][1] == 'r' || argv[i][1] == 'R') reformshort = 1;
  50.          else
  51.             err = 3;
  52.          if (!err) {
  53.             --argc;
  54.             for (j = i--; j < argc; j++) argv[j] = argv[j+1];
  55.             }
  56.          }
  57.    if (argc != 3 && argc != 2) err = 3;
  58.    }
  59.    
  60. if (err) {
  61.    fputs("REFORMAT by Unicorn Research Corporation\nReformat a text file with new line lengths.\n\nUsage:  Reformat [-r] [-lN] [-tM] infile [outfile]\n\n", stdout);
  62.    fputs("-r = re-wrap lines shorter than N (default is to leave them alone)\n N = the new line length (minimum 32, default 72)\n M = the tab width (maximum 30, assumed 8)\n\n", stdout);
  63.    fputs("If outfile is omitted, then infile will be replaced.\nThe end-of-line code in the text file must be compatible with your\noperating system -- use StripCR / AddCR as necessary.\n", stdout);
  64.    return;
  65.    }
  66. if ((infile = fopen( argv[1], (replace = (argc == 2)) ? "r+" : "r" )) == NULL) {
  67.    fputs("Could not open input file.\n", stdout);
  68.    return;
  69.    }
  70. if (replace)
  71.    outfile = infile;
  72. else if ((outfile = fopen( argv[2], "w" )) == NULL) {
  73.    fputs("Could not open output file.\n", stdout);
  74.    fclose(infile);
  75.    return;
  76.    }
  77. if ((buf = (signed char *)malloc(outbufsiz)) == NULL) {
  78.    fputs("Not enough memory!\n", stdout);
  79.    goto cleanup;
  80.    }
  81.  
  82. for (inpos = 0; inpos < 3; inpos++)  /* read first three characters */
  83.    if ((lk[inpos] = fgetc(infile)) == EOF)
  84.       { err = 2;  goto clean2; }
  85. buf[bufptr++] = lk[0];               /* record first char in output buffer */
  86. if (!isspace(lk[0]))
  87.    ++lineptr;
  88. else if (lk[0] == '\t') lineptr += tabwidth;
  89.  
  90. /* the cntinu flag is confusing.  If 1, that means the current OUTPUT line
  91.  * has wrapped while reading the current INPUT line.
  92.  */
  93. do {  /* process the file */
  94.    plast = (ptr + 2) % 3;    /* index of next character */
  95.    pnext = (ptr + 1) % 3;    /* index of previous character */
  96.    if (cntinu && !lineptr && isspace(lk[ptr]) && lk[ptr] != '\n') {
  97.       ptr = pnext;
  98.       continue;
  99.       }
  100.    if (lk[ptr] != '\n'                              /* if not newline */
  101.        || (lk[ptr] == '\n' &&                       /* or if newline and */
  102.        (isspace(lk[pnext]) || lk[plast] == '\n'))){ /* whitespace, then */
  103.       if (lk[ptr] == '\t')                          /* first ajust for */
  104.          lineptr = ((lineptr+tabwidth)/tabwidth)*tabwidth;
  105.       else if (lk[ptr] == '\n') lineptr=cntinu=0;   /* new character or */
  106.       else ++lineptr;
  107.       if (lineptr >= linelength) {                  /* a possible tab, */
  108.          if (isspace(lk[ptr])) {                    /* check if line */
  109.             if (lk[ptr] != '\n') {
  110.                lk[ptr] = '\n';                      /* length exceeded */
  111.                cntinu = 1;
  112.                lineptr = 0;
  113.                }
  114.             else cntinu = 0; 
  115.             }
  116.          else {                                     /* w/nonwhite space */
  117.             for (j = bufptr-1; j > 0; j--)          /* (in which case */
  118.                if (isspace(buf[j])) break;          /* go back & insert */
  119.             if (j) buf[j] = '\n';                   /* a newline), */
  120.             cntinu = 1;
  121.             lineptr = bufptr - 1 - j;               /* and after reset */
  122.             }                                       /* of lineptr we */
  123.          }                                          /* will put the char */
  124.       buf[bufptr++] = lk[ptr];                      /* into the buffer. */
  125.       if (replace) inpos = ftell(infile);
  126.       if (bufptr == outbufsiz) if (err = writebuf()) break;
  127.       }
  128.    else {  /* otherwise substitute a space for the newline */
  129.       if ((!reformshort && !cntinu) || lineptr+1 >= linelength) {
  130.          buf[bufptr++] = '\n';
  131.          lineptr = 0;
  132.          }
  133.       else {
  134.          buf[bufptr++] = ' ';
  135.          ++lineptr;
  136.          }
  137.       cntinu = 0;
  138.       if (replace) inpos = ftell(infile);
  139.       if (bufptr == outbufsiz) if (err = writebuf()) break;
  140.       }
  141.    ptr = pnext;
  142.    } while ((lk[plast] = fgetc(infile)) != EOF);
  143.  
  144. buf[bufptr++] = lk[pnext];     /* grab the last character */
  145. while (!err && bufptr) {
  146.    inpos = outpos + bufptr;    /* reset to allow remaining writes */
  147.    err = writebuf();
  148.    }
  149.  
  150. clean2:
  151. if (err == 1)
  152.    fputs("Error writing output file.\n", stdout);
  153. else if (err == 2)
  154.    fputs("Error reading input file.\n", stdout);
  155. else if (replace) {
  156.    fseek(outfile, outpos, 0);
  157.    fputc('\x1A', outfile);
  158.    fputs(argv[1], stdout);
  159.    fputs(" is now reformatted.\nDelete any text after the ctrl-Z.\n", stdout);
  160.    }
  161. else {
  162.    fputs("Reformatted file ", stdout);
  163.    fputs(argv[2], stdout);
  164.    fputs(" successfully created.\n", stdout);
  165.    }
  166.  
  167. cleanup:
  168. free(buf);
  169. fclose(infile);
  170. if (!replace) fclose(outfile);
  171. }
  172.  
  173.  
  174. /* Write the buffer to the output file, when full or when done.
  175.  * Stop writing when end of buffer is hit, or, if we are in replace mode,
  176.  * when current input pointer is hit. */
  177. int writebuf()
  178. {
  179. unsigned short i = 0, j = 0, k = 0, buflimit;
  180. if (replace) {
  181.    if ((buflimit = inpos - outpos) <= 0) return -100;
  182.    /* For the next buffer fill, we may need to back up a bit and
  183.     * insert a newline.  So, we dump out just half the buffer. */
  184.    if (bufptr >= outbufsiz) buflimit = (buflimit >> 1) + 1;
  185.    if (fseek(outfile, outpos, 0)) return 1;
  186.    }
  187. else
  188.    buflimit = bufptr;
  189.  
  190. /* this loop is used either in replace or create mode, so we'll avoid
  191.    using ftell() -- we will just assume that all EOLs are 2 characters */
  192.  
  193. while (i < buflimit) {
  194.    if (fputc(buf[k++], outfile) == EOF) return 1;
  195.    if (buf[i++] == '\n') 
  196.       if (++i >= buflimit) break; /* safety if we have 2-char EOLs */
  197.    }                              /* k is the number of characters written */
  198.  
  199. if (replace) {
  200.    outpos = ftell(outfile);
  201.    if (fseek(infile, inpos, 0)) return 2;
  202.    }
  203.  
  204. /* shift remaining contents of buffer to the beginning of it */
  205. i = k;
  206. while (i < bufptr) buf[j++] = buf[i++];
  207. bufptr -= k;
  208. return 0;
  209. }
  210.